﻿#include "MainWindow.h"

#include <QFileDialog>
#include <QMessageBox>

#include "ais/ais_mesh.h"
#include "cmd/cmd_curve.h"
#include "cmd/cmd_mesh.h"
#include "cmd/cmd_projection.h"
#include "cmd/cmd_shade.h"
#include "cmd/cmd_surface.h"
#include "qt_renderer.h"
#include "topo/topo_all.h"

using namespace CAGD;

// 预定义宏
#define CAGD_CONNECT_SLOT(slot, method) QObject::connect(ui.slot, SIGNAL(triggered()), this, SLOT(method()));
#define CAGD_CONNECT_COMMAND(command)                                                                                  \
    QObject::connect(ui.action##command, SIGNAL(triggered()), this, SLOT(CreateCommand()));                            \
    factory.RegisterProduct(#command, Cmd##command::CreateCommand);
#define CAGD_CONNECT_RENDERER(type, renderer) factory.RegisterProduct(type, CAGD::Shd##renderer::CreateRenderer);

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    ui.setupUi(this);

    // 文件
    CAGD_CONNECT_SLOT(actionOpen, Open)
    CAGD_CONNECT_SLOT(actionSave, Save)
    CAGD_CONNECT_SLOT(actionClear, Clear)

    // =========================================================================================
    {
        RendererFactory &factory = RendererFactory::CreateFactory();

        // 链接渲染器，每个 AIS_Type 都要对应一种着色器
        CAGD_CONNECT_RENDERER(AIS_Type::POINT, Point)
        CAGD_CONNECT_RENDERER(AIS_Type::POINTCLOUD, PointCloud)
        CAGD_CONNECT_RENDERER(AIS_Type::VECTOR, Vector)
        CAGD_CONNECT_RENDERER(AIS_Type::VECTORCLOUD, VectorCloud)
        CAGD_CONNECT_RENDERER(AIS_Type::BOX, Box)
        CAGD_CONNECT_RENDERER(AIS_Type::CURVE, Curve)
        CAGD_CONNECT_RENDERER(AIS_Type::MESH, Mesh)
        CAGD_CONNECT_RENDERER(AIS_Type::SURFACE, Surface)
        CAGD_CONNECT_RENDERER(AIS_Type::POLE, Pole)
        CAGD_CONNECT_RENDERER(AIS_Type::POINTLIGHT, PointLight)
        CAGD_CONNECT_RENDERER(AIS_Type::DIRLIGHT, DirLight)
        CAGD_CONNECT_RENDERER(AIS_Type::SPOTLIGHT, SpotLight)
        CAGD_CONNECT_RENDERER(AIS_Type::CAMERA, Point)
        CAGD_CONNECT_RENDERER(AIS_Type::FRAME, Frame)
    }

    // =========================================================================================
    {
        CommandFactory &factory = CommandFactory::CreateFactory();

        // 图元
        CAGD_CONNECT_COMMAND(Point)
        CAGD_CONNECT_COMMAND(Vector)

        // 渲染
        CAGD_CONNECT_COMMAND(PointLight)
        CAGD_CONNECT_COMMAND(DirLight)
        CAGD_CONNECT_COMMAND(SpotLight)
        CAGD_CONNECT_COMMAND(Camera)

        // 曲线
        CAGD_CONNECT_COMMAND(Lagrange)

        CAGD_CONNECT_COMMAND(Bezier)
        CAGD_CONNECT_COMMAND(BezierFit)
        CAGD_CONNECT_COMMAND(BezierDyn)

        CAGD_CONNECT_COMMAND(BSpline)
        CAGD_CONNECT_COMMAND(BSplineFit)
        CAGD_CONNECT_COMMAND(BSplineIntp)
        CAGD_CONNECT_COMMAND(BSplineLane)
        CAGD_CONNECT_COMMAND(BSplineDivide)

        // 曲面
        CAGD_CONNECT_COMMAND(BSplineSurface)

        // 投影
        CAGD_CONNECT_COMMAND(NearPointCurve)
        CAGD_CONNECT_COMMAND(OrthoPointCurve)
        CAGD_CONNECT_COMMAND(NearPointSurface)
        CAGD_CONNECT_COMMAND(OrthoPointSurface)
        CAGD_CONNECT_COMMAND(TorusPointSurface)
        CAGD_CONNECT_COMMAND(MarchCurveSurface)
        CAGD_CONNECT_COMMAND(ODECurveSurface)

        // 网格
        CAGD_CONNECT_COMMAND(FFD)
        CAGD_CONNECT_COMMAND(QEM)
    }
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    ui.openGLWidget->resize({event->size().width(), event->size().height() - 40});
}

void MainWindow::Open()
{
    QString filename = QFileDialog::getOpenFileName(this, "Choose Model", CAGD_RC_PATH, "OBJ (*.obj *.dat)");
    if (filename != "")
    {
        Handle(TopoMesh) m;
        if (filename.contains(".obj"))
            m = load_from_obj(filename.toStdString());
        if (filename.contains(".dat"))
            m = load_from_dat(filename.toStdString());

        Handle(AIS_Mesh) mesh(new AIS_Mesh(m));
        AIS_Context::ShareContext().CreateObject(mesh);
        update();
    }
}

void MainWindow::Save()
{
    QString filename = QFileDialog::getSaveFileName(this, "Choose Path", CAGD_RC_PATH, "OBJ (*.obj)");
}

void MainWindow::Clear()
{
}

void MainWindow::CreateCommand()
{
    // 获得信号发起者，并获得标签名
    QAction *action = qobject_cast<QAction *>(sender());
    QString command = action->text();

    AIS_Context::ShareContext().CreateCommand(command.toStdString());
}